package com.csproj.basic.service;

import com.csproj.basic.BasicService;
import com.csproj.basic.domain.ElectronicLock;
import com.csproj.basic.domain.ElectronicLockMessage;
import com.csproj.basic.domain.Site;
import com.csproj.basic.repository.ElectronicLockMessageRepository;
import com.csproj.basic.repository.ElectronicLockRepository;
import com.csproj.basic.repository.SiteRepository;
import com.csproj.basic.service.dto.ElectronicLockDTO;
import com.csproj.basic.service.mapper.ElectronicLockMapper;
import com.csproj.basic.service.mapper.ElectronicLockMessageMapper;
import com.csproj.dispatch.domain.Dispatch;
import com.csproj.dispatch.repository.DispatchRepository;
import com.csproj.dispatch.service.DispatchService;
import com.csproj.dispatch.service.dto.DispatchDTO;
import com.csproj.dispatch.service.mapper.DispatchMapper;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.exception.BaseAppException;
import com.csproj.siiat.base.common.util.FileUtils;
import com.csproj.siiat.base.common.util.poi.POIUtil;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.service.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing ElectronicLock.
 */
@Service
@Transactional
public class ElectronicLockService extends BasicService<ElectronicLockDTO> {

    private final Logger log = LoggerFactory.getLogger(ElectronicLockService.class);

    private final ElectronicLockRepository electronicLockRepository;
    private final ElectronicLockMessageRepository electronicLockMessageRepository;

    private final ElectronicLockMapper electronicLockMapper;
    private final ElectronicLockMessageMapper electronicLockMessageMapper;
    private final UserInfoService userInfoService;

    private final SiteRepository siteRepository;

    private final DispatchRepository dispatchRepository;

    private final DispatchMapper dispatchMapper;

    private final DispatchService dispatchService;

    public ElectronicLockService(ElectronicLockRepository electronicLockRepository,
                                 ElectronicLockMapper electronicLockMapper, UserInfoService userInfoService, SiteRepository siteRepository,
                                 ElectronicLockMessageRepository electronicLockMessageRepository,
                                 ElectronicLockMessageMapper electronicLockMessageMapper,
                                 DispatchRepository dispatchRepository,
                                 DispatchMapper dispatchMapper,
                                 DispatchService dispatchService) {
        this.electronicLockRepository = electronicLockRepository;
        this.electronicLockMapper = electronicLockMapper;
        this.electronicLockMessageMapper =electronicLockMessageMapper;
        this.userInfoService = userInfoService;
        this.siteRepository = siteRepository;
        this.electronicLockMessageRepository = electronicLockMessageRepository;
        this.dispatchRepository = dispatchRepository;
        this.dispatchMapper = dispatchMapper;
        this.dispatchService = dispatchService;
    }

    /**
     * 保存电子关锁信息并且返回前端需要发的dto，包括扩展属性createName
     * @param electronicLockDTO
     * @return electronicLockDTO
     * TODO 主要负责从前端接收值
     * TODO 其他业务方法，比如保存试卷时同时保存章节
     * TODO DTO的扩展属性，在此方法复制
     */
    public ElectronicLockDTO saveAndGetDTO(ElectronicLockDTO electronicLockDTO) {
        ElectronicLock electronicLock = electronicLockMapper.toEntity(electronicLockDTO);
        electronicLock.setState(ElectronicLock.STATUS_UNUSED);
        electronicLock = save(electronicLock);
        electronicLockDTO = electronicLockMapper.toDto(electronicLock);

        //扩展字端
        extendSiteName(electronicLockDTO);
        extendStateNameOfElectronicLock(electronicLockDTO);
        return electronicLockDTO;
    }

    /**
     * 保存电子关锁信息
     * @param electronicLock
     * @return electronicLock
     * TODO 纯粹的保存方法，通用于所有保存业务调用
     * TODO 赋默认值，保存后，检查数据库，是否所有字段都有准确值
     */
    public ElectronicLock save(ElectronicLock electronicLock) {
        ElectronicLock entity = electronicLockRepository.findFirstByLockNoAndDeletedFlagIsFalse(electronicLock.getLockNo());

        if(StringUtils.isNotBlank(electronicLock.getId())){
            if(entity!=null && !entity.getId().equals(electronicLock.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(entity!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }
        electronicLock.setNowSiteId(electronicLock.getSiteId());
        electronicLock.setEnableFlag(true);
        electronicLock.setCreationTime(ZonedDateTime.now());
        electronicLock.setCreatorUserId(SecurityUtils.getCurrentUserId());
        electronicLock.setLastModificationTime(ZonedDateTime.now());
        electronicLock.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        electronicLock.setDeletedFlag(false);
        return electronicLockRepository.save(electronicLock);
    }

    /**
     * 获取所有电子关锁信息
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<ElectronicLockDTO> findAll() {
        List<ElectronicLockDTO> result = electronicLockRepository.findAll().stream()
                .map(electronicLockMapper::toDto)
                .collect(Collectors.toCollection(LinkedList::new));
        return result;
    }

    /**
     * 获取所有电子关锁信息
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<ElectronicLockDTO> findAllAndMessage(String siteId) {
        List<ElectronicLockDTO> result = new ArrayList<>();
        if(StringUtils.isNotBlank(siteId))
        {
            result = electronicLockRepository.findBySiteIdAndMessage(siteId).stream()
                    .map(electronicLockMapper::toDto)
                    .collect(Collectors.toCollection(LinkedList::new));
        }
        else
        {
            result = electronicLockRepository.findAllSiteIdAndMessage().stream()
                    .map(electronicLockMapper::toDto)
                    .collect(Collectors.toCollection(LinkedList::new));
        }


        for(ElectronicLockDTO electronicLockDTO : result){
            //获取实时信息
            ElectronicLockMessage electronicLockMessage = electronicLockMessageRepository.findFirstByElNumberOrderByTimeDesc(electronicLockDTO.getLockNo());
            electronicLockDTO.setElectronicLockMessageDTO(electronicLockMessageMapper.toDto(electronicLockMessage));
            //获取对应调度信息
            Dispatch dispatch = dispatchRepository.findFirstByLockCodeAndDeletionTimeIsNullAndArriveTimeIsNullOrderByCreationTimeDesc(electronicLockDTO.getLockNo());
            DispatchDTO dispatchDTO = dispatchMapper.toDto(dispatch);
            dispatchService.extendLaunchsiteName(dispatchDTO);
            dispatchService.extendDestinationsiteName(dispatchDTO);
            electronicLockDTO.setDispatchDTO(dispatchDTO);
        }
        return result;
    }
    /**
     *  获取所有电子关锁信息（分页）
     *  @return the list of entities
     *
     *  TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public Page<ElectronicLock> findPageList(Map<String, Object> map, Pageable pageable) {
        Page<ElectronicLock> result = electronicLockRepository.findPageList(map,pageable);
        return result;
    }

    /**
     *  获取所有电子关锁信息（分页）
     *  @return the list of entities
     *
     */
    @Transactional(readOnly = true)
    public BaseDTO findPageListAndGetDTO(Map<String,Object> map, Pageable pageable) {
        //根据角色确认查询
        String siteId = userInfoService.getCurrentUserSiteId();
        if(map.get("siteId")==null){
            map.put("siteId",siteId);
        }
        Page<ElectronicLock> result = findPageList(map,pageable);
        List<ElectronicLock> devices = result.getContent();
        List<ElectronicLockDTO> dto = electronicLockMapper.toDto(devices);

        //扩展字端
        extendStateNameOfElectronicLock(dto);
        extendSiteName(dto);

        dto.stream().forEach(m->{
            ElectronicLockMessage used = electronicLockMessageRepository.findFirstByElNumberOrderByTimeDesc(m.getLockNo());
            if(used==null)
                m.setHasUsed(false);
            else
                m.setHasUsed(true);
        });
        return BaseDTO.createBaseDTO(result).setFieldList(dto);
    }


    /**
     * 根据id，获取电子关锁信息
     *  @param id 主键id
     *  @return creator、questionTypeName
     *
     *  TODO 返回DTO，包含扩展属性
     *  TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public ElectronicLockDTO findOneAndGetDTO(String id) {
        ElectronicLock entity = findOne(id);
        ElectronicLockDTO dto = electronicLockMapper.toDto(entity);

        //扩展字端
        extendSiteName(dto);
        extendStateNameOfElectronicLock(dto);
        return dto;
    }

    /**
     * 根据id，获取电子关锁信息
     *  @param id the id of the entity
     *  @return the entity
     *
     *  TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public ElectronicLock findOne(String id) {
        ElectronicLock entity = electronicLockRepository.findOne(id);
        if(entity == null){
            throw new BaseAppException(BaseDTO.CODE_PARAM,"id有错误");
        }
        return entity;
    }

    /**
     * 修改电子关锁并且返回前端需要发的dto，包括扩展属性
     * @param dto
     * @return dto
     * TODO 类似SAVE
     */
    public ElectronicLockDTO updateAndGetDTO(ElectronicLockDTO dto) {
        ElectronicLock entity = electronicLockMapper.toEntity(dto);
        entity = update(entity);
        ElectronicLockDTO result = electronicLockMapper.toDto(entity);

        extendSiteName(result);
        extendStateNameOfElectronicLock(result);
        return result;
    }


    /**
     *  根据id，删除电子关锁信息
     *  @param id the id of the entity
     */
    public void delete(String id) {
        ElectronicLock entity = findOne(id);
        entity.setState("1");
        entity.setDeletedFlag(true);
        entity.setDeletionTime(ZonedDateTime.now());
        entity.setDeleterUserId(SecurityUtils.getCurrentUserId());
        entity = electronicLockRepository.save(entity);
    }

    /**
     * 修改电子关锁
     * @param entity
     * @return warehouse
     * TODO 类似SAVE
     */
    public ElectronicLock update(ElectronicLock entity) {
        ElectronicLock model = electronicLockRepository.findFirstByLockNoAndDeletedFlagIsFalse(entity.getLockNo());

        if(StringUtils.isNotBlank(entity.getId())){
            if(model!=null && !model.getId().equals(entity.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }else if(model!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }

        ElectronicLock deviceDB = findOne(entity.getId());

        deviceDB.setSiteId(entity.getSiteId());
        deviceDB.setSimNum(entity.getSimNum());
        deviceDB.setLockNo(entity.getLockNo());
        deviceDB.setLastModificationTime(ZonedDateTime.now());
        deviceDB.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        deviceDB = electronicLockRepository.save(deviceDB);
        return deviceDB;
    }

    /**
     *  获取状态
     *  @param id the id of the entity
     */
    public ElectronicLockDTO status(String id,boolean enable) {
        ElectronicLock entity = findOne(id);
        entity.setEnableFlag(enable);

        entity.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        entity.setLastModificationTime(ZonedDateTime.now());
        entity = electronicLockRepository.save(entity);
        ElectronicLockDTO result = electronicLockMapper.toDto(entity);

        extendSiteName(result);
        extendStateNameOfElectronicLock(result);
        return result;

    }

    /**
     *  获取状态
     *  @param dto y
     */
    public ElectronicLockDTO updateElectronicStatus(ElectronicLockDTO dto) {
        ElectronicLock entity = findOne(dto.getId());
        entity.setEnableFlag(dto.getEnableFlag());
        entity.setReason(dto.getReason());
        entity.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        entity.setLastModificationTime(ZonedDateTime.now());
        entity = electronicLockRepository.save(entity);
        ElectronicLockDTO result = electronicLockMapper.toDto(entity);
        return result;

    }


    /**
     * 上传文件
     * @param file
     */
    public String uploadFile(HttpServletRequest request, MultipartFile file){
        String filePath = FileUtils.excelUpload(request,file, File.separator+"upload"+ File.separator+"site");
        return filePath;
    }

    /**
     * 获取统计数量 （未分配与在途数量）
     * @return
     */
    public Map<String, Object> findElectronicLockStatistics(String siteIdParam) {
        Map<String,Object> map = new HashMap<>();
        //获取未分配数量
        String siteId =  userInfoService.getCurrentUserSiteId();
        if(StringUtils.isNotBlank(siteId)){
            List<ElectronicLock> electronicLocksTransit = electronicLockRepository.findByStatusAndSiteIdAndEnbaleFlag(ElectronicLock.STATUS_USED, siteId,true);
            map.put("inTransit",electronicLocksTransit.size());
            List<ElectronicLock> electronicLocks = electronicLockRepository.findBySiteIdAndEnbleFlag(siteId,true);
            map.put("totalCount",electronicLocks.size());
        }else{
            List<ElectronicLock> electronicLocksUnAllot=null;
            List<ElectronicLock> electronicLocksTransit=null;
            List<ElectronicLock> electronicLocks=null;
            if(StringUtils.isNotBlank(siteIdParam))
            {
                electronicLocksUnAllot = electronicLockRepository.findBySiteIdAndEnbleFlag(siteIdParam,true);
                electronicLocksTransit = electronicLockRepository.findByStatusAndSiteIdAndEnbaleFlag(ElectronicLock.STATUS_USED,siteIdParam,true);
                electronicLocks = electronicLockRepository.findBySiteIdAndEnbleFlag(siteIdParam,true);
            }
            else{
                electronicLocksUnAllot = electronicLockRepository.findByUnAlloat();
                //获取在途数量
                electronicLocksTransit = electronicLockRepository.findByStatus(ElectronicLock.STATUS_USED);
                electronicLocks = electronicLockRepository.findAll();
            }
            map.put("unAllot",electronicLocksUnAllot.size());
            map.put("inTransit",electronicLocksTransit.size());
            map.put("totalCount",electronicLocks.size());
        }
        String siteName = "";
        if(StringUtils.isNotBlank(siteId)){
            Site site = siteRepository.findById(siteId);
            if(site!=null){
                siteName = site.getSiteName();
            }
        }
        map.put("siteName",siteName);
        return map;

    }

    /**
     * 上传文件
     * @param file
     */
    public BaseDTO  batchImport(MultipartFile file){
        try {
            List<String[]> readResult = POIUtil.readExcel(file);

            if(readResult.size()==0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("upload_faild");
            }
            List<ElectronicLock> eles = new ArrayList<>();
            List<Site> sites = siteRepository.findAll();
            StringBuilder errmsg = new StringBuilder();
            int i = 2;
            for (String[] u : readResult) {
                try {
                    ElectronicLock uname = electronicLockRepository.findFirstByLockNoAndDeletedFlagIsFalse(u[0]);
                    if(uname!=null){
                        errmsg.append(i-1).append(",");
                    }else{

                        ElectronicLock ele = new ElectronicLock();
                        i++;
                        ele.setDeletedFlag(false);
                        ele.setEnableFlag(true);
                        ele.setLockNo(u[0]);
                        ele.setSimNum(u[1]);
                        if(StringUtils.isNotBlank(u[2]))
                        {
                            Site site = sites.stream().filter(s->s.getSiteName().equals(StringUtils.trim(u[2]))).findFirst().orElse(new Site());
                            ele.setSiteId(site.getId());
                        }
                        eles.add(ele);
                    }

                }catch (Exception e){
                    errmsg.append(i-1).append(",");
                }
            }

            if(eles.size()>0)
                electronicLockRepository.save(eles);
            String msg = "";
            if(errmsg.length()>0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("partial_upload_faild");
            }
        } catch (IOException e) {
            throw new BaseAppException(false,"upload_error");
        }
        return BaseDTO.createBaseDTO().setSuccess(true);
    }
}
